package EA.recording;
import RKUjava.datastructures.RKUVector;
import java.util.Enumeration;

/** Defines a 2D table useful for recording data. */
public class SequenceTable implements ConvertToText
{

  /** Contains a number of SequenceTableColumn's. 
      First one is the identity column, the rest are data. */
  public RKUVector datasequences;

  /** True if the identity column is an autoincrement column. */
  public boolean autoincrement;

  /** The startvalue for the identity. (Only used if autoincrement is true)
   */
  public double startvalue;

  /** The stepsize for the identity. (Only used if autoincrement is true)
   */
  public double stepsize;

  /** The current value of the identity. */
  public double curvalue;

  /** Is this the first reading of the curvalue? */
  boolean firstreading;

  /** The base filename is the first part of the filename when the data is
      stored by the BatchJobScheduler. */
  public String basefilename;

  /** The number of recorded rows in this SequenceTable. */
  public int numberofrows;

  /** Create a new SequenceTable. You have to create a SequenceTableColumn 
      and set it with setIdentityColumn(). */
  public SequenceTable(String abasefilename)
    {
      super();
      datasequences = new RKUVector();
      autoincrement = false;
      numberofrows = 0;
      basefilename = abasefilename;
    }

  /** Create a new SequenceTable. This will set autoincrement to true and
      create the necessary identity column. */
  public SequenceTable(String abasefilename, double astartvalue, double astepsize)
    {
      super();
      datasequences = new RKUVector();

      autoincrement = true;
      stepsize = astepsize;
      startvalue = astartvalue;
      curvalue = startvalue;
      firstreading = true;
      numberofrows = 0;
      basefilename = abasefilename;

      datasequences.addElement(new SequenceTableColumn("ID"));
    }

  /** Set the identity column. */
  public void setIdentityColumn(SequenceTableColumn idcolumn)
    {
      if (datasequences.size()>0) {
	datasequences.setElementAt(idcolumn,0);
      }
      else {
	datasequences.addElement(idcolumn);
      }
    }


  /** Add a column to this table. */
  public void addColumn(SequenceTableColumn column)
    {
      // fill the column with nulls if to short
      while (column.size()<numberofrows) {
	column.recordData(null);
      };

      datasequences.addElement(column);
    }

  /** Add a number of columns to this table. */
  public void addColumns(SequenceTableColumn[] columns)
    {

      for (int i=0;i<columns.length;i++) {
	addColumn(columns[i]);
      }
    }

  /** Add a number of columns to this table.
   @param num The number of columns to add.
   @param header The header for the columns. A number will be appended
   to the header, e.g., "peak "+i.*/
  public void addColumns(int num, String header)
    {
      for (int i=0;i<num;i++) {
	addColumn(new SequenceTableColumn(header+i));
      }
    }


  /** Record a row of data. If you don't use automatic increasing of 
      the identity column then the first entry in the array must be
      the id-value. If you want to skip fields put a null in those you
      want to skip.
  */
  public void recordData(Object[] thedata)
    {
      int i, j;
      SequenceTableColumn curseq;

      i = 0;
      j = 0;

      // Set the identity col
      if (!autoincrement) {
	curseq = (SequenceTableColumn)datasequences.elementAt(i);
	curseq.recordData(thedata[j]);
	j++;
      }
      else {
	if (firstreading) {
	  firstreading = false;
	}
	else {
	  curvalue += stepsize;
	};
	curseq = (SequenceTableColumn)datasequences.elementAt(i);
	curseq.recordData(new Double(curvalue));
      };
      i++;

      for (;j<thedata.length;j++) {
	curseq = (SequenceTableColumn)datasequences.elementAt(i);
	curseq.recordData(thedata[j]);
      }

      numberofrows++;
    }

  /** Add and initialize an empty row to the table. 
      This can be used in connection with the updateLastRow methods. */
  public void initializeRow()
    {
      int i;
      SequenceTableColumn curseq;

      i = 0;

      // Set the identity col
      if (autoincrement) {
	if (firstreading) {
	  firstreading = false;
	}
	else {
	  curvalue += stepsize;
	};
	curseq = (SequenceTableColumn)datasequences.elementAt(i);
	curseq.recordData(new Double(curvalue));
	i++;
      };


      while(i<datasequences.size()) {
	curseq = (SequenceTableColumn)datasequences.elementAt(i);
	curseq.recordData(null);
	i++;
      }

      numberofrows++;
    }

  /** Update an entry in the last row of the table. 
      @param index The index to update. (0 is the identity.)
      @param data The object to insert at <tt>index</tt> in the last row.
  */
  public void updateLastRow(int index, Object data)
    {
      SequenceTableColumn curseq;

      curseq = (SequenceTableColumn)datasequences.elementAt(index);
      curseq.updateLastRow(data);
    }

  /** Update an entry in the last row of the table. 
      @param index The index to update. (0 is the identity.)
      @param data The double to insert at <tt>index</tt> in the last row.
      It will be wrapped in a Double object.
  */
  public void updateLastRow(int index, double data)
    {
      SequenceTableColumn curseq;

      curseq = (SequenceTableColumn)datasequences.elementAt(index);
      curseq.updateLastRow(new Double(data));
    }

  /** Update an entry in the last row of the table. 
      @param index The index to update. (0 is the identity.)
      @param data The integer to insert at <tt>index</tt> in the last row.
      It will be wrapped in a Integer object.
  */
  public void updateLastRow(int index, int data)
    {
      SequenceTableColumn curseq;

      curseq = (SequenceTableColumn)datasequences.elementAt(index);
      curseq.updateLastRow(new Integer(data));
    }

  /** Update an number of entries in the last row of the table. 
      @param index The index to start at. (0 is the identity.)
      @param data The objects to insert from <tt>index</tt> and on.
  */
  public void updateLastRow(int index, Object[] data)
    {
      SequenceTableColumn curseq;

      for (int i=0;i<data.length;i++) {
	curseq = (SequenceTableColumn)datasequences.elementAt(index+i);
	curseq.updateLastRow(data[i]);
      }
    }

  /** Update an number of entries in the last row of the table. 
      @param index The index to start at. (0 is the identity.)
      @param data The doubles to insert from <tt>index</tt> and on.
      They will be wrapped in Double objects.
  */
  public void updateLastRow(int index, double[] data)
    {
      SequenceTableColumn curseq;

      for (int i=0;i<data.length;i++) {
	curseq = (SequenceTableColumn)datasequences.elementAt(index+i);
	curseq.updateLastRow(new Double(data[i]));
      }
    }

  /** Update an number of entries in the last row of the table. 
      @param index The index to start at. (0 is the identity.)
      @param data The integers to insert from <tt>index</tt> and on.
      They will be wrapped in Integer objects.
  */
  public void updateLastRow(int index, int[] data)
    {
      SequenceTableColumn curseq;

      for (int i=0;i<data.length;i++) {
	curseq = (SequenceTableColumn)datasequences.elementAt(index+i);
	curseq.updateLastRow(new Integer(data[i]));
      }
    }

  /** Update an entry in the last row of the table. 
      @param name The name of the column to update.
      @param data The object to insert in the column in the last row.
  */
  public void updateLastRow(String name, Object data)
    {
      SequenceTableColumn curseq;
      Enumeration ennum;

      for (ennum = datasequences.elements();ennum.hasMoreElements();) {
	curseq = (SequenceTableColumn)ennum.nextElement();
	if (name.equals(curseq.getName())) {
	  curseq.updateLastRow(data);
	  return;
	}
      }
      System.out.println("WARNING: SequenceTable.updateLastRow()\nCould not find column with name= \""+name+"\"");
    }

  /** Clear the recorded data. This method remove the data from all columns.
   */
  public void clearData()
    {
      for(Enumeration ennum= datasequences.elements();ennum.hasMoreElements();) {
	((SequenceTableColumn)ennum.nextElement()).clearData();
      }

      // Reset auto ID
      curvalue = startvalue;
      firstreading = true;
      numberofrows = 0;
    }

  /** Get a column. */
  public SequenceTableColumn getColumn(int i)
    {
      return (SequenceTableColumn)datasequences.elementAt(i);
    };


  /** Get the basefilename. */
  public String getBasefilename()
    {
      return basefilename;
    }

  /** Convert the data to a delimited textstring. */
  public String convertDataToDelimited(String columndelim, String rowdelim, String prependtorow)
    {
      StringBuffer res = new StringBuffer();
      int i, j;
      int numberofrows, numberofcols;

      // Print data

      numberofrows = ((SequenceTableColumn)datasequences.elementAt(0)).size();
      numberofcols = datasequences.size();
      for (i=0; i<numberofrows;i++) {
	res.append(prependtorow);
	for (j=0; j<numberofcols;j++) {
	  res.append(((SequenceTableColumn)datasequences.elementAt(j)).getReadingAsText(i));
	  if (!(j == numberofcols-1)) {
	    res.append(columndelim);
	  }
	  else {
	    res.append(rowdelim);
	  };
	};
      };

      return res.toString();
    };

  /** Convert the headings to a delimited textstring. */
  public String convertHeadingsToDelimited(String columndelim, String rowdelim, String prependtorow)
    {
      StringBuffer res = new StringBuffer();
      int i, j;
      int numberofrows, numberofcols;

      // Print names
      res.append(prependtorow);
      for (i=0; i<datasequences.size();i++) {
	res.append(((SequenceTableColumn)datasequences.elementAt(i)).getName());
	if (!(i == datasequences.size()-1)) {
	  res.append(columndelim);
	}
	else {
	  res.append(rowdelim);
	}
      }
      return res.toString();
    }

  /** Convert the data to a textstring according to the GNUPlot format. */
  public String convertToGNUPlot()
    {
      return "";
    };
}
